#include "UVSphere.h"

UVSphere::UVSphere(const Vector3& _center, float _radius, Texture* _tex)
	: center(_center), radius(_radius), tex(_tex)
{

}

bool UVSphere::hit(const Ray& r, float tmin, float tmax, float time, HitRecord &record) const
{
	//	compute A, B and C
	Vector3 oc = r.origin() - center;

	float A = r.direction().squaredLength();
	float inv2A = 0.5f / A;
	float B = 2 * dot(r.direction(), oc);
	float C = oc.squaredLength() - radius * radius;

	//	compute delta
	float delta = B * B - 4 * A * C;
	if (delta <= 0.0f) return false;
	float sdelta = sqrt(delta);

	float t;
	//	if C is positive, compute the smaller root
	if (C > 0.0f)	
		t = inv2A * (-B - sdelta);
	else	// compute the bigger root
		t = inv2A * (-B + sdelta);
	if (t < tmin || t > tmax) return false;

	//	we have a valid hit
	record.t = t;
	Vector3 n = record.normal = (r(t) - center) / radius;
	//	decide the position of the hit point
	record.hit_p = r(t);
	//	calculate UV coords
	float theta = acos(n.z());
	float phi = atan2(n.y(), n.x());
	if (phi < 0.0f) phi += 2 * PI;

	record.uv = Vector2(phi * INV_PI * 0.5f, (PI - theta) * INV_PI);
	record.hit_tex = tex;
	return true;
}

bool UVSphere::shadowHit(const Ray& r, float tmin, float tmax, float time) const
{
	//	compute A, B and C
	Vector3 oc = r.origin() - center;

	float A = r.direction().squaredLength();
	float inv2A = 0.5f / A;
	float B = 2 * dot(r.direction(), oc);
	float C = oc.squaredLength() - radius * radius;

	//	compute delta
	float delta = B * B - 4 * A * C;
	if (delta <= 0.0f) return false;
	float sdelta = sqrt(delta);

	float t;
	//	if C is positive, compute the smaller root
	if (C > 0.0f)	
		t = inv2A * (-B - sdelta);
	else	// compute the bigger root
		t = inv2A * (-B + sdelta);
	if (t < tmin || t > tmax) return false;
	return true;
}